/*
 * @filename GlobalExceptionHandler.java
 * @author barry
 * @version 0.0.1
 * @date 2020年1月19日
 */
package com.bnzj.core.webflux.exception;

import javax.annotation.Resource;
import javax.validation.ValidationException;

import com.bnzj.core.config.CoreProperties;
import com.bnzj.core.exception.BusinessException;
import com.bnzj.core.rest.ResponseResult;
import com.bnzj.core.rest.ResultCode;
import com.bnzj.core.util.FbConstant;
import com.bnzj.core.util.LogUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.server.ServerWebExchange;

import lombok.extern.slf4j.Slf4j;

/**
 * @author barry
 * @date 2020-01-19
 */
@Slf4j
@RestControllerAdvice
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class GlobalExceptionHandler {

    @Resource
    private CoreProperties coreProperties;
    
    private void printLog(String uri, Exception e) {
        log.error(FbConstant.LINE_SEPARATOR + "---" + Thread.currentThread().getStackTrace()[2].toString());
        if (coreProperties.isDeveloperMode()) {
            log.error(uri, e);
        } else {
            LogUtils.error(log, uri, e, 20);
        }
    }

    /**
     * 处理其他未处理的异常
     * @param req
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = Exception.class)
    public ResponseResult<String> defaultErrorHandler(ServerWebExchange serverWebExchange, Exception e) {
        printLog(serverWebExchange.getRequest().getURI().toString(), e);
        return ResponseResult.failure(ResultCode.UNKNOWN, e.getMessage());
    }
    
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = AsyncRequestTimeoutException.class)
    public void asyncRequestTimeoutExceptionHandler(ServerWebExchange serverWebExchange, AsyncRequestTimeoutException e) {
        printLog(serverWebExchange.getRequest().getURI().toString(), e);
    }
    
    /**
     * 处理数据校验异常
     * @param req
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
    @ExceptionHandler(value = {ValidationException.class, MethodArgumentNotValidException.class, MethodArgumentTypeMismatchException.class})
    public ResponseResult<?> handleMethodArgumentNotValidException(ServerWebExchange serverWebExchange, Exception e) {
        printLog(serverWebExchange.getRequest().getURI().toString(), e);
        return ResponseResult.failure(ResultCode.BAD_REQUEST, e.getMessage());
    }
    
    /**
     * 处理业务异常
     * @param req
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.NOT_EXTENDED)
    @ExceptionHandler(value = BusinessException.class)
    public ResponseResult<?> handleBusinessException(ServerWebExchange serverWebExchange, BusinessException e) {
        printLog(serverWebExchange.getRequest().getURI().toString(), e);
        return ResponseResult.bizException(e);
    }
}
